# -*- coding:utf8 -*-
import json
import traceback
import os
import re
import time
import base64
import requests
from typing import Optional, Callable, MutableMapping
from scrapy import Request, FormRequest
from squirrel_core.commons.utils.tools import calc_str_md5, upload_file
from squirrel_core.frame.spider_makaka import MakakaSpider

file_path = os.environ.get("FILE_PATH", "/")


class wotu_pic(MakakaSpider):
    name = "wotu_pic"
    serialNumber = ""
    all_flag = False
    need_ssdbstore_dup = True
    header = {
        "Host": "m.alltuu.com",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
        "accept": "application/json",
        "content-type": "application/x-www-form-urlencoded",
        "Referer": "https://m.alltuu.com/"
    }
    cmpt_id_dict = {
        "2025若尔盖国家公园天边小路越野赛": "2160521204",
        "2025凯乐石东北100松花湖跑山赛": "1735041253",
        "北京三峰之巅越野赛": "1761576313"
    }
    album_id = ""
    retry_time = 3

    def get_ext_requests_or_urls(self, data=None):
        if data and isinstance(data, str):
            data = json.loads(data)
        if data and isinstance(data, MutableMapping):
            self.serialNumber = data.get("serialNumber", "")
            self.all_flag = data.get("spider_config", {}).get("all", False)
            race_id = data.get("spider_config", {}).get("race_id", "")
            user_id = data.get("spider_config", {}).get("user_id", "")
            race_no = data.get("spider_config", {}).get("race_no", "")
            race_name = data.get("spider_config", {}).get("race_name", "")
            source_url = data.get("spider_config", {}).get("url", "")
            pic_base64 = data.get("spider_config", {}).get("pic_base64", "")
            if not race_no and not pic_base64:
                self.logger.info("参赛号或头像必须有一个")
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 101, "message": "缺失参赛号或头像，请仔细核对"})
                self.close_after_idle = True
                self.force_to_close_spider = True
            else:
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 100, "message": "任务启动成功"})
                if "m.alltuu.com" in source_url:
                    self.album_id = "".join(re.findall(r"album/(.*)?/", source_url)).strip()
                else:
                    self.album_id = self.cmpt_id_dict.get(race_name)
                time_stamp = int(time.time() * 1000)
                s = calc_str_md5(f"/{self.album_id}/100002/{time_stamp}/null/0")
                url = f"https://m.alltuu.com/rest/fc/authority/v100002-{time_stamp}-null-0-{s}?albumId={self.album_id}"
                yield Request(url=url, callback=self.parse, dont_filter=True, errback=self.err_parse, headers=self.header,
                              meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                    "time_stamp": time_stamp, "pic_base64": pic_base64})

    def parse(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        time_stamp = response.meta.get("time_stamp", "")
        pic_base64 = response.meta.get("pic_base64", "")
        try:
            self.logger.info(f"开始获取secret key:{response.url}")
            content = json.loads(response.text).get("data", {})
            secret = content.get("secret", "")
            if pic_base64:
                a1 = self.i()
                d = self.f(a1)
                s1 = f"/{self.album_id}/100002/{d}/{time_stamp}/null/1/2"
                s = calc_str_md5(s1)
                url = f"https://ai.alltuu.com/fr/ntauth/v100002-{time_stamp}-null-2-{s} "
                data = {"u": "1", "p": d, "a": self.album_id}
                yield FormRequest(url=url, callback=self.parse_upload, dont_filter=True, errback=self.err_parse,
                                  formdata=data,
                                  meta={"race_id": race_id, "race_no": race_no, "user_id": user_id,
                                        "race_name": race_name, "pic_base64": pic_base64,
                                        "time_stamp": time_stamp, "secret": secret})
            signature_str = f"/{self.album_id}/60/100002/1/{secret}/{race_no}/{time_stamp}/null/0"
            sign_str = calc_str_md5(signature_str)
            u_str = f"/v100002-{time_stamp}-null-0-{sign_str}"
            url = f"https://ama.alltuu.com/rest/v4/num/search/a{self.album_id}/c60/p1/t{race_no}/sk{secret}{u_str}"
            yield Request(url=url, callback=self.parse_secret, dont_filter=True, errback=self.err_parse,
                          meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name})
        except Exception:
            self.logger.info(f"获取secret key时出错{response.url}：{traceback.format_exc()}")

    def parse_upload(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        secret = response.meta.get("secret", "")
        pic_base64 = response.meta.get("pic_base64", "")
        try:
            self.logger.info(f"开始上传头像")
            content = json.loads(response.text).get("data", {})
            pic_name = calc_str_md5(pic_base64)
            file_data = base64.b64decode(pic_base64)
            formdata = {
                "name": content.get("OSSParams").get("key"),
                "key": content.get("OSSParams").get("dir") + content.get("OSSParams").get("key"),
                "policy": content.get("OSSParams").get("policy"),
                "OSSAccessKeyId": content.get("OSSParams").get("accessid"),
                "success_action_status": "200",
                "callback": content.get("OSSParams").get("callback"),
                "signature": content.get("OSSParams").get("signature")
            }
            files = {
                "file": (pic_name, file_data, "image/png")
            }
            requests.post("https://aii.alltuu.com/", data=formdata, files=files)
            time_stamp = int(time.time() * 1000)
            k = content.get("OSSParams").get("key").split(".")[0]
            s1 = f"/{self.album_id}/100002/{k}/0/{time_stamp}/null/1/2"
            s = calc_str_md5(s1)
            url = f"https://aai.alltuu.com/fr/ntscan/v100002-{time_stamp}-null-2-{s}"
            data = {"u": "1", "p": k, "a": self.album_id, "s": "0"}
            yield FormRequest(url=url, callback=self.parse_check_pic, dont_filter=True, errback=self.err_parse,
                              formdata=data,
                              meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                    "secret": secret, "post_url": url, "post_data": data})
        except Exception:
            self.logger.info(f"上传头像时出错：{traceback.format_exc()}")

    def parse_check_pic(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        secret = response.meta.get("secret", "")
        post_url = response.meta.get("post_url", "")
        post_data = response.meta.get("post_data", {})
        try:
            self.logger.info(f"开始获取头像id")
            content = json.loads(response.text)
            if content.get("msg", "") == "成功" and not content.get("data", {}).get("face_list", []):
                self.logger.info(f"===post_url:{post_url}，{content}")
                self.retry_time -= 1
                if self.retry_time > 0:
                    yield FormRequest(url=post_url, callback=self.parse_check_pic, dont_filter=True, errback=self.err_parse,
                                      formdata=post_data,
                                      meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                            "secret": secret, "post_url": post_url, "post_data": post_data})
            else:
                face_id = content.get("data", {}).get("face_list", [])[0].get("face_id", "")
                time_stamp = int(time.time() * 1000)
                s1 = f"/{self.album_id}/60/{face_id}/100002/1/0/{secret}/{time_stamp}/null/1/4"
                s = calc_str_md5(s1)
                url = f"https://ama.alltuu.com/rest/v4/fr/ntsearch/new/v100002-{time_stamp}-null-4-{s}"
                data = {
                    "a": self.album_id,
                    "u": "1",
                    "f": face_id,
                    "s": "0",
                    "cnt": "60",
                    "pag": "1",
                    "version": "4",
                    "sk": secret
                }
                yield FormRequest(url=url, callback=self.parse_secret, dont_filter=True, errback=self.err_parse,
                                  formdata=data,
                                  meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name,
                                        "time_stamp": time_stamp})
        except Exception:
            self.logger.info(f"获取头像id时出错：{traceback.format_exc()}")

    def parse_secret(self, response, **kwargs):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        try:
            self.logger.info(f"开始查找{race_no}的照片:{response.url}")
            content = json.loads(response.text).get("d", {})
            pic_list = content.get("list", [])
            if pic_list:
                for pic in pic_list:
                    status = True
                    if pic.get("name", ""):
                        status = self.server.set_add(f'{self.name}:storedupefilter', calc_str_md5(pic.get("name", "")))
                        if self.all_flag:
                            status = True
                        if not status:
                            self.logger.info("重复照片")
                    if status:
                        pic_url = pic.get("bl", "")
                        if pic_url:
                            yield Request(url=pic_url, callback=self.parse_pic, errback=self.err_parse, dont_filter=self.all_flag,
                                          meta={"race_id": race_id, "race_no": race_no, "user_id": user_id, "race_name": race_name})
            else:
                self.logger.info(f"没找到{race_no}的照片")

                result = self.send_data(resp=response, serial_number=self.serialNumber,
                                        user_id=user_id, race_id=race_id)
                yield result
        except Exception:
            self.logger.info(f"查找{race_no}的照片时出错{response.url}：{traceback.format_exc()}")

    def parse_pic(self, response):
        race_id = response.meta.get("race_id", "")
        user_id = response.meta.get("user_id", "")
        race_no = response.meta.get("race_no", "")
        race_name = response.meta.get("race_name", "")
        try:
            self.logger.info(f"开始下载{race_no}的照片：{response.url}")
            pic_md5 = calc_str_md5(response.url)
            pic_name = f"{race_no}_{pic_md5}.jpg"
            dir_path = os.path.join(file_path, "picture", self.name_first)
            if not os.path.exists(dir_path):
                os.makedirs(dir_path)
            save_path = os.path.join(dir_path, pic_name)
            if not os.path.exists(save_path):
                with open(save_path, "wb") as f:
                    f.write(response.body)
                upload_path = f"flow/{race_id}/{user_id}/pic/{pic_name}"
                upload_flag = upload_file(save_path, upload_path)
                if upload_flag:
                    self.logger.info(f"{save_path}上传成功：{upload_path}")
                else:
                    self.logger.info(f"{save_path}上传失败：{upload_path}")
                result_dict = {"pic_name": pic_name, "pic_type": "jpg", "url_address": upload_path, "race_id": race_id, "race_name": race_name}

                result = self.send_data(resp=response, serial_number=self.serialNumber, result_data=result_dict,
                                        user_id=user_id, race_id=race_id, dup_str=str(result_dict))
                yield result
        except Exception:
            self.logger.info(f"下载{race_no}照片时出错{response.url}：{traceback.format_exc()}")

    def send_data(self, resp=None, serial_number=None, result_data=None, user_id=None, race_id=None, dup_str=None):
        if result_data is None:
            result_data = {"msg": "未查到照片信息"}
        result_dict = {"serialNumber": serial_number, "webType": self.name_first,
                       "userId": user_id, "raceId": race_id, "code": 200,
                       "crawlerType": self.name_second, "data": str(result_data)}
        result = self.result_item_assembler(resp)
        result['result_data'] = result_dict
        if not self.all_flag and dup_str is not None:
            result['_dup_str'] = calc_str_md5(dup_str)
        return result

    def i(self) -> bytearray:
        o = bytearray(16)
        r: Optional[Callable[[bytearray], bytearray]] = None
        if r is None:
            try:
                def urandom_wrapper(buf: bytearray) -> bytearray:
                    buf[:] = os.urandom(len(buf))
                    return buf
                r = urandom_wrapper
            except:
                try:
                    pass
                except:
                    pass
            if r is None:
                raise RuntimeError(
                    "Secure random number generation not supported. "
                    "See https://github.com/uuidjs/uuid#getrandomvalues-not-supported"
                )
        return r(o)

    def f(self, e, t=0):
        u = [
            "00",
            "01",
            "02",
            "03",
            "04",
            "05",
            "06",
            "07",
            "08",
            "09",
            "0a",
            "0b",
            "0c",
            "0d",
            "0e",
            "0f",
            "10",
            "11",
            "12",
            "13",
            "14",
            "15",
            "16",
            "17",
            "18",
            "19",
            "1a",
            "1b",
            "1c",
            "1d",
            "1e",
            "1f",
            "20",
            "21",
            "22",
            "23",
            "24",
            "25",
            "26",
            "27",
            "28",
            "29",
            "2a",
            "2b",
            "2c",
            "2d",
            "2e",
            "2f",
            "30",
            "31",
            "32",
            "33",
            "34",
            "35",
            "36",
            "37",
            "38",
            "39",
            "3a",
            "3b",
            "3c",
            "3d",
            "3e",
            "3f",
            "40",
            "41",
            "42",
            "43",
            "44",
            "45",
            "46",
            "47",
            "48",
            "49",
            "4a",
            "4b",
            "4c",
            "4d",
            "4e",
            "4f",
            "50",
            "51",
            "52",
            "53",
            "54",
            "55",
            "56",
            "57",
            "58",
            "59",
            "5a",
            "5b",
            "5c",
            "5d",
            "5e",
            "5f",
            "60",
            "61",
            "62",
            "63",
            "64",
            "65",
            "66",
            "67",
            "68",
            "69",
            "6a",
            "6b",
            "6c",
            "6d",
            "6e",
            "6f",
            "70",
            "71",
            "72",
            "73",
            "74",
            "75",
            "76",
            "77",
            "78",
            "79",
            "7a",
            "7b",
            "7c",
            "7d",
            "7e",
            "7f",
            "80",
            "81",
            "82",
            "83",
            "84",
            "85",
            "86",
            "87",
            "88",
            "89",
            "8a",
            "8b",
            "8c",
            "8d",
            "8e",
            "8f",
            "90",
            "91",
            "92",
            "93",
            "94",
            "95",
            "96",
            "97",
            "98",
            "99",
            "9a",
            "9b",
            "9c",
            "9d",
            "9e",
            "9f",
            "a0",
            "a1",
            "a2",
            "a3",
            "a4",
            "a5",
            "a6",
            "a7",
            "a8",
            "a9",
            "aa",
            "ab",
            "ac",
            "ad",
            "ae",
            "af",
            "b0",
            "b1",
            "b2",
            "b3",
            "b4",
            "b5",
            "b6",
            "b7",
            "b8",
            "b9",
            "ba",
            "bb",
            "bc",
            "bd",
            "be",
            "bf",
            "c0",
            "c1",
            "c2",
            "c3",
            "c4",
            "c5",
            "c6",
            "c7",
            "c8",
            "c9",
            "ca",
            "cb",
            "cc",
            "cd",
            "ce",
            "cf",
            "d0",
            "d1",
            "d2",
            "d3",
            "d4",
            "d5",
            "d6",
            "d7",
            "d8",
            "d9",
            "da",
            "db",
            "dc",
            "dd",
            "de",
            "df",
            "e0",
            "e1",
            "e2",
            "e3",
            "e4",
            "e5",
            "e6",
            "e7",
            "e8",
            "e9",
            "ea",
            "eb",
            "ec",
            "ed",
            "ee",
            "ef",
            "f0",
            "f1",
            "f2",
            "f3",
            "f4",
            "f5",
            "f6",
            "f7",
            "f8",
            "f9",
            "fa",
            "fb",
            "fc",
            "fd",
            "fe",
            "ff"
        ]
        uuid_str = (
            f"{u[e[t + 0]]}{u[e[t + 1]]}{u[e[t + 2]]}{u[e[t + 3]]}-"
            f"{u[e[t + 4]]}{u[e[t + 5]]}-"
            f"{u[e[t + 6]]}{u[e[t + 7]]}-"
            f"{u[e[t + 8]]}{u[e[t + 9]]}-"
            f"{u[e[t + 10]]}{u[e[t + 11]]}{u[e[t + 12]]}{u[e[t + 13]]}{u[e[t + 14]]}{u[e[t + 15]]}"
        ).lower()
        return uuid_str

    def err_parse(self, failure):
        self.logger.warning(f"请求失败：{failure.request.url},错误原因:{traceback.format_exc()}")

